#!/bin/bash
#===============================================================================
# redis.sh
#
# Control the redis databases.
#===============================================================================

test -x ./config.sh && . ./config.sh &>/dev/null

# Check that the necessary configuration settings are available.

if [ "${REDIS_LOCAL_DIR}" == "" ] ; then
	echo "Setting \${REDIS_LOCAL_DIR} is not set"
	exit 1
fi

if [ "${REDIS_GREEN_HOST}" == "" ] ; then
	echo "Setting \${REDIS_GREEN_HOST} is not set"
	exit 1
fi

if [ "${REDIS_GREEN_PORT}" == "" ] ; then
	echo "Setting \${REDIS_GREEN_PORT} is not set"
	exit 1
fi

if [ "${REDIS_DISTR_HOST}" == "" ] ; then
	echo "Setting \${REDIS_DISTR_HOST} is not set"
	exit 1
fi

if [ "${REDIS_DISTR_PORT}" == "" ] ; then
	echo "Setting \${REDIS_DISTR_PORT} is not set"
	exit 1
fi

if [ "${REDIS_LOGGER_HOST}" == "" ] ; then
	echo "Setting \${REDIS_LOGGER_HOST} is not set"
	exit 1
fi

if [ "${REDIS_LOGGER_PORT}" == "" ] ; then
	echo "Setting \${REDIS_LOGGER_PORT} is not set"
	exit 1
fi

if [ "${HOST_USERNAME}" == "" ] ; then
	echo "Setting \${HOST_USERNAME} is not set"
	exit 1
fi

#-------------------------------------------------------------------------------
# Explain the command line options to the user.
#-------------------------------------------------------------------------------

function SHOW_OPTIONS() {
	EXIT_CODE=${1} ; shift

	cat <<EOF
Usage: ${0} <command> [<which-server>]

Commands:
  start    Start the redis server(s)
  stop     Stop the redis server(s)
  info     Show status info about the redis server(s)
  flush    Flush the redis server(s)
  help     Show this message and exit

Which-server:
  green    Only act upon the Green redis server
  distr    Only act upon the redis server for the count tree
  logger   Only act upon the redis server for the logging
  all      Act on all redis servers
  (no server specification is equivalent to "all")

EOF
	exit ${EXIT_CODE}
}

#-------------------------------------------------------------------------------
# Check if a particular host is reachable over the network.  If the host is
# reachable, the function has an exit code of 0.  If not, the exit code is 1.
#-------------------------------------------------------------------------------

function CHECK_ALIVE() {
	HOST=${1} ; shift

	ping -t 4 -o -q ${HOST} >/dev/null
}

#-------------------------------------------------------------------------------
# Check if a particular redis database is already running.  If the server is
# running, the function has an exit code of 0.  If not, the exit code is 1.
#-------------------------------------------------------------------------------

function CHECK_RUNNING() {
	HOST=${1} ; shift
	PORT=${1} ; shift

	nc -z -w5 ${HOST} ${PORT} &>/dev/null && return 0 || return 1
}

#-------------------------------------------------------------------------------
# Check if a particular redis database is not running.  If the server is not
# running, the function has an exit code of 0.  Otherwise, the exit code is 1.
#-------------------------------------------------------------------------------

function CHECK_NOT_RUNNING() {
	HOST=${1} ; shift
	PORT=${1} ; shift

	nc -z -w5 ${HOST} ${PORT} &>/dev/null && return 1 || return 0
}

#-------------------------------------------------------------------------------
# Start a redis database on a specified server.
#-------------------------------------------------------------------------------

function START_SERVER() {
	MESSAGE=${1} ; shift
	HOST=${1} ; shift
	PORT=${1} ; shift
	DIR=${1} ; shift
	TEMP=`mktemp -t START_SERVER`

	echo "==== ${MESSAGE} ===="
	CHECK_ALIVE ${HOST} \
	|| { echo "  Could not reach host ${HOST}" ; rm -f ${TEMP} ; return ; } \
	&& CHECK_NOT_RUNNING ${HOST} ${PORT} \
	|| { echo "  Server is already running on ${HOST}:${PORT}" ; rm -f ${TEMP} ; return ; } \
	&& ssh ${HOST_USERNAME}@${HOST} "cd ${DIR} ; ./redis-server --port ${PORT} --daemonize yes" &>${TEMP} \
	|| { echo "  Encountered an error!" ; echo "  Output:" ; cat ${TEMP} ; rm -f ${TEMP} ; return ; } \
	&& { echo "  Started" ; rm -f ${TEMP} ; }
}

#-------------------------------------------------------------------------------
# Stop a redis database on a specified server.
#-------------------------------------------------------------------------------

function STOP_SERVER() {
	MESSAGE=${1} ; shift
	HOST=${1} ; shift
	PORT=${1} ; shift
	TEMP=`mktemp -t STOP_SERVER`

	echo "==== ${MESSAGE} ===="
	CHECK_ALIVE ${HOST} \
	|| { echo "  Could not reach host ${HOST}" ; rm -f ${TEMP} ; return ; } \
	&& CHECK_RUNNING ${HOST} ${PORT} \
	|| { echo "  Server is not running on ${HOST}:${PORT}" ; rm -f ${TEMP} ; return ; } \
	&& ${REDIS_LOCAL_DIR}/redis-cli -h ${HOST} -p ${PORT} shutdown &>${TEMP} \
	|| { echo "  Encountered an error!" ; echo "  Output:" ; cat ${TEMP} ; rm -f ${TEMP} ; return ; } \
	&& { echo "  Stopped" ; rm -f ${TEMP} ; }
}

#-------------------------------------------------------------------------------
# Flush a redis database server.
#-------------------------------------------------------------------------------

function FLUSH_SERVER() {
	MESSAGE=${1} ; shift
	HOST=${1} ; shift
	PORT=${1} ; shift
	TEMP=`mktemp -t FLUSH_SERVER`

	echo "==== ${MESSAGE} ===="
	CHECK_ALIVE ${HOST} \
	|| { echo "  Could not reach host ${HOST}" ; rm -f ${TEMP} ; return ; } \
	&& CHECK_RUNNING ${HOST} ${PORT} \
	|| { echo "  Server is not running on ${HOST}:${PORT}" ; rm -f ${TEMP} ; return ; } \
	&& ${REDIS_LOCAL_DIR}/redis-cli -h ${HOST} -p ${PORT} flushdb &>${TEMP} \
	|| { echo "  Encountered an error!" ; echo "  Output:" ; cat ${TEMP} ; rm -f ${TEMP} ; return ; } \
	&& { echo "  Flushed" ; rm -f ${TEMP} ; }
}

#-------------------------------------------------------------------------------
# Display information about a redis database server.
#-------------------------------------------------------------------------------

function INFO_SERVER() {
	MESSAGE=${1} ; shift
	HOST=${1} ; shift
	PORT=${1} ; shift
	TEMP=`mktemp -t INFO_SERVER`

	echo "==== ${MESSAGE} ===="
	echo "  Host: ${HOST}"
	echo "  Port: ${PORT}"
	CHECK_ALIVE ${HOST} \
	|| { echo "  Could not reach host ${HOST}" ; rm -f ${TEMP} ; return ; } \
	&& CHECK_RUNNING ${HOST} ${PORT} \
	|| { echo "  Server is not running on ${HOST}:${PORT}" ; rm -f ${TEMP} ; return ; } \
	&& ${REDIS_LOCAL_DIR}/redis-cli -h ${HOST} -p ${PORT} info &>${TEMP} \
	|| { echo "  Could not connect to host ${HOST}" ; rm -f ${TEMP} ; return ; } \
	&& { egrep "(db0:)|(process_id:)|(uptime_in_seconds:)|(used_memory_human:)|(total_commands_processed:)" ${TEMP} | sed -e 's,^,  ,' ; rm -f ${TEMP} ; }
}

#-------------------------------------------------------------------------------
# Start the appropriate redis database servers as specified on the command
# line.
#-------------------------------------------------------------------------------

function START_SERVERS() {
	if [ "${WHICH}" == "all" ] ; then
		START_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT} ${REDIS_GREEN_DIR}
		START_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT} ${REDIS_DISTR_DIR}
		START_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT} ${REDIS_LOGGER_DIR}
	elif [ "${WHICH}" == "green" ] ; then
		START_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT} ${REDIS_GREEN_DIR}
	elif [ "${WHICH}" == "distr" ] ; then
		START_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT} ${REDIS_DISTR_DIR}
	elif [ "${WHICH}" == "logger" ] ; then
		START_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT} ${REDIS_LOGGER_DIR}
	else
		echo "!!! Something bad has gone wrong (line ${LINENO})"
		exit 1
	fi
}

#-------------------------------------------------------------------------------
# Stop the appropriate redis database servers as specified on the command line.
#-------------------------------------------------------------------------------

function STOP_SERVERS() {
	if [ "${WHICH}" == "all" ] ; then
		STOP_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT}
		STOP_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT}
		STOP_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT}
	elif [ "${WHICH}" == "green" ] ; then
		STOP_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT}
	elif [ "${WHICH}" == "distr" ] ; then
		STOP_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT}
	elif [ "${WHICH}" == "logger" ] ; then
		STOP_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT}
	else
		echo "!!! Something bad has gone wrong (line ${LINENO})"
		exit 1
	fi
}

#-------------------------------------------------------------------------------
# Flush the appropriate redis database servers as specified on the command
# line.
#-------------------------------------------------------------------------------

function FLUSH_SERVERS() {
	if [ "${WHICH}" == "all" ] ; then
		FLUSH_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT}
		FLUSH_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT}
		FLUSH_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT}
	elif [ "${WHICH}" == "green" ] ; then
		FLUSH_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT}
	elif [ "${WHICH}" == "distr" ] ; then
		FLUSH_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT}
	elif [ "${WHICH}" == "logger" ] ; then
		FLUSH_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT}
	else
		echo "!!! Something bad has gone wrong (line ${LINENO})"
		exit 1
	fi
}

#-------------------------------------------------------------------------------
# Display information about the appropriate redis database servers as specified
# on the command line.
#-------------------------------------------------------------------------------

function INFO_SERVERS() {
	if [ "${WHICH}" == "all" ] ; then
		INFO_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT}
		INFO_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT}
		INFO_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT}
	elif [ "${WHICH}" == "green" ] ; then
		INFO_SERVER "redis_green" ${REDIS_GREEN_HOST} ${REDIS_GREEN_PORT}
	elif [ "${WHICH}" == "distr" ] ; then
		INFO_SERVER "redis_distr" ${REDIS_DISTR_HOST} ${REDIS_DISTR_PORT}
	elif [ "${WHICH}" == "logger" ] ; then
		INFO_SERVER "redis_logger" ${REDIS_LOGGER_HOST} ${REDIS_LOGGER_PORT}
	else
		echo "!!! Something bad has gone wrong (line ${LINENO})"
		exit 1
	fi
}

#-------------------------------------------------------------------------------
# Process the command line options.
#-------------------------------------------------------------------------------

COMMAND=${1} ; shift
WHICH=${1} ; shift

# If no server is specified, default to "all"

if [ "${WHICH}" == "" ] ; then
	WHICH=all
fi

# Check that the specified server is legal.

case ${WHICH} in
	green) ;;
	distr) ;;
	logger) ;;
	all ) ;;
	*    ) echo "Error in command-line options" ; SHOW_OPTIONS 1 ;;
esac

# Check that there is some command.

if [ "${COMMAND}" == "" ] ; then
	echo "No command given"
	SHOW_OPTIONS 1
fi

# Check if there are any extra options.

if [ "${*}" != "" ] ; then
	echo "Unrecognized option \"${1}\""
	SHOW_OPTIONS 1
fi

#-------------------------------------------------------------------------------
# Execute the given command.
#-------------------------------------------------------------------------------

case ${COMMAND} in
	help ) SHOW_OPTIONS 0 ;;
	start) START_SERVERS ;;
	stop ) STOP_SERVERS ;;
	info ) INFO_SERVERS ;;
	flush) FLUSH_SERVERS ;;
	*    ) echo "Unknown command \"${COMMAND}\"" ; SHOW_OPTIONS 1 ;;
esac

#===============================================================================
# End of redis.sh
#===============================================================================
